﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Windows.Threading;

namespace Xceed.Silverlight.Data
{
  internal static class DispatcherSynchronizationContextExtensions
  {
    internal static void InvokeAction( this DispatcherSynchronizationContext source, Action d )
    {
      CallInfo callInfo = new CallInfo( d );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T>(
      this DispatcherSynchronizationContext source,
      Action<T> d,
      T arg )
    {
      CallInfo callInfo = new CallInfo( d, arg );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2> d,
      T1 arg1,
      T2 arg2 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3> d,
      T1 arg1,
      T2 arg2,
      T3 arg3 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14,
      T15 arg15 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static void InvokeAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14,
      T15 arg15,
      T16 arg16 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16 );

      DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<TResult>(
      this DispatcherSynchronizationContext source,
      Func<TResult> d )
    {
      CallInfo callInfo = new CallInfo( d );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T, TResult> d,
      T arg )
    {
      CallInfo callInfo = new CallInfo( d, arg );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, TResult> d,
      T1 arg1,
      T2 arg2 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(
      this DispatcherSynchronizationContext source,
      Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14,
      T15 arg15 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    internal static TResult InvokeFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(
      this DispatcherSynchronizationContext source,
      Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> d,
      T1 arg1,
      T2 arg2,
      T3 arg3,
      T4 arg4,
      T5 arg5,
      T6 arg6,
      T7 arg7,
      T8 arg8,
      T9 arg9,
      T10 arg10,
      T11 arg11,
      T12 arg12,
      T13 arg13,
      T14 arg14,
      T15 arg15,
      T16 arg16 )
    {
      CallInfo callInfo = new CallInfo( d, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16 );

      return ( TResult )DispatcherSynchronizationContextExtensions.Invoke( source, callInfo );
    }

    private static object Invoke( DispatcherSynchronizationContext source, CallInfo callInfo )
    {
      if( source == null )
        throw new ArgumentNullException( "source" );

      if( callInfo == null )
        throw new ArgumentNullException( "callInfo" );

      try
      {
        source.Send( DispatcherSynchronizationContextExtensions.InvokeCallback, callInfo );
      }
      catch( Exception e )
      {
        callInfo.Error = e;
      }

      if( callInfo.Error != null )
        throw new DataInternalException( callInfo.Error );

      return callInfo.ReturnValue;
    }

    private static void InvokeCallback( object state )
    {
      CallInfo callInfo = ( CallInfo )state;

      try
      {
        callInfo.ReturnValue = callInfo.Delegate.DynamicInvoke( callInfo.Parameters );
      }
      catch( Exception e )
      {
        callInfo.Error = e;
      }
    }

    #region CallInfo Nested Type

    private class CallInfo
    {
      internal CallInfo( Delegate d )
      {
        if( d == null )
          throw new ArgumentNullException( "d" );

        this.Delegate = d;
      }

      internal CallInfo( Delegate d, params object[] parameters )
        : this( d )
      {
        this.Parameters = parameters;
      }

      internal Delegate Delegate
      {
        get;
        private set;
      }

      internal object[] Parameters
      {
        get;
        private set;
      }

      internal object ReturnValue
      {
        get;
        set;
      }

      internal Exception Error
      {
        get;
        set;
      }
    }

    #endregion
  }
}
